use rand::Rng;
use std::cmp::Ordering;
use std::io;
use std::{thread, time};

/*
获取输入数据， method 2
*/
macro_rules! input_num_macros {
    () => {
            {
                println!("input_num_macros");

                let mut input = String::new();

                io::stdin()
                    .read_line(&mut input)
                    .expect("Falied to read line");

                input
        }
    };
}

// 编写一个函数，该函数接收一个字符串，并返回在该字符串中找到的第一个单词。
// 如果函数在该字符串中并未找到空格，则整个字符串就是一个单词，所以应该返回整个字符串。
// 如果函数在该字符串中找到空格， 则返回空格前的单词。
fn main() {
    println!("Hello, world!");

//     // method 1
//     let input_val: String = getInput();
//     println!("getInput recive input_val:{}", input_val);
// //    // or method 2
//     let nn = input_num_macros!();
//     println!("input_num_macros recive nn:{}", nn);
//    // or method 3
    let mut input_valRefer = String::new();
    let returnVal = getInputRefer(&mut input_valRefer);
    println!("getInputRefer recive input_valRefer:{}", input_valRefer);
    // println!("getInputRefer recive returnVal:{}", returnVal);

    // 返回单词结尾的索引
    let idx = first_word(&input_valRefer);
    // 输出第一个单词, 实际位置为  [0, idx)
    println!("first_word get:{}/{}.", idx, &input_valRefer[0..idx]);

    // 返回单词结尾的索引
    // let mt_string = "aaaaa";
    // let sliceStr = first_word_slice(mt_string);
    let sliceStr = first_word_slice(&input_valRefer);
    println!("first_word get:{}.", sliceStr);


    // 数组：
    let a = [1, 2, 3, 4, 5];

    // 我们想要引用数组的一部分。可以这样做：
    let slice = &a[1..3]; // 实际位置为 [1, 3)
    assert_eq!(slice, &[2, 3]);
}

/*
获取输入数据， method 1
*/
fn getInput() -> String{
    let mut inputVal = String::new();

    println!("Please getInput key:");
    io::stdin()
        .read_line(&mut inputVal)
        .expect("error input");
    // println!("getInput recive value:{}", inputVal);

    inputVal
}

/*
获取输入数据， method 3
*/
fn getInputRefer(val : &mut String) -> String{
    println!("Please getInputRefer key:");
    io::stdin()
        .read_line(val)
        .expect("error input");
    // println!("getInputRefer recive val:{}", val);

    val.to_string()
}

/*
返回该字符串的第一个单词的下标。
该写法中下标与值s是没有联系的， 当s清空或者失效时， 下标也就没有使用的意义和场景了
==> 关联的解决方案：Rust 为这个问题提供了一个解决方法   字符串 slice。
*/
fn first_word(s: &String) -> usize{
    // 因为需要逐个元素的检查 String 中的值是否为空格，需要用 as_bytes 方法将 String 转化为字节数组
    let bytes = s.as_bytes();

    // 使用 iter 方法在字节数组上创建一个迭代器
    // iter 方法返回集合中的每一个元素，
    // enumerate 包装了 iter 的结果，将这些元素作为元组来返回。 返回的元组中，第一个元素是索引，第二个元素是集合中元素的引用。
    // item 为引用， 所以为 &item
    for (us, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return us;
        }
    }

    s.len()
}

/*
返回该字符串的第一个单词
“字符串 slice” 的类型声明写作 &str
*/
// 签名 1
// fn first_word_slice(s: &String) -> &str{
// 签名 2: 而更有经验的 Rustacean 会编写出如下签名，因为它使得可以对 String 值和 &str 值使用相同的函数
fn first_word_slice(s: &str) -> &str{
    // 因为需要逐个元素的检查 String 中的值是否为空格，需要用 as_bytes 方法将 String 转化为字节数组
    let bytes = s.as_bytes();

    // 使用 iter 方法在字节数组上创建一个迭代器
    // iter 方法返回集合中的每一个元素，
    // enumerate 包装了 iter 的结果，将这些元素作为元组来返回。 返回的元组中，第一个元素是索引，第二个元素是集合中元素的引用。
    // item 为引用， 所以为 &item
    for (us, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            // 实际位置为  [0, us)
            return &s[..us];
        }
    }

    &s[..]
}